package com.partsoft.webs.zks;

import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.event.EventListener;
import org.zkoss.zk.ui.event.Events;
import org.zkoss.zk.ui.ext.AfterCompose;

/**
 * 公用的数据组件基础类<br/>
 * 用于定义非include等于false的宏组件
 * 
 * @author neeker
 */
@SuppressWarnings({ "serial" })
public abstract class BlockMacroComponent extends org.zkoss.zk.ui.HtmlMacroComponent {

	/**
	 * 克隆组合后事件名称
	 */
	public static final String ON_AFTER_CLONE = "onCloneAfterCompose";

	/**
	 * 数据模型参数名
	 */
	public static final String ARG_DATAMODEL = "dataModel";

	/**
	 * 数据已经装载事件
	 */
	public static final String ON_DATALOAD = "onDataLoad";

	private boolean alreadyCompose;

	public BlockMacroComponent() {
		super();
	}

	/**
	 * 始终设置inline等于false
	 */
	@Override
	final public boolean isInline() {
		return false;
	}

	/**
	 * 编程创建数据宏组件构造函数
	 * 
	 * @param macroURI
	 */
	public BlockMacroComponent(String macroURI) {
		this.setMacroURI(macroURI);
	}

	/**
	 * 编程创建数据宏组件构造函数
	 * 
	 * @param parent
	 *            指定父组件
	 * @param macroURI
	 */
	public BlockMacroComponent(Component parent, String macroURI) {
		this.setMacroURI(macroURI);
	}

	/**
	 * 下属子组件组合后被调用
	 */
	@Override
	public void afterCompose() {
		if (isAlreadyCompose())
			return;
		beforeCreateMacroChildren();
		super.afterCompose();
		afterCreateMacroChildren();
		this.alreadyCompose = true;
	}

	/**
	 * 在创建宏组件之前被调用方法
	 */
	protected void beforeCreateMacroChildren() {
	}

	/**
	 * 在创建宏组件之后被调用的方法
	 */
	protected void afterCreateMacroChildren() {
	}

	/**
	 * 重新创建方法
	 */
	@Override
	public void recreate() {
		alreadyCompose = false;
		super.recreate();
	}

	/**
	 * 由于Macro实现了{@link AfterCompose}接口，因此创建之后会重入{@link #afterCompose()}
	 * 
	 * @return 返回true表示已经调用了组合方法
	 */
	final public boolean isAlreadyCompose() {
		return alreadyCompose;
	}

	@Override
	public Object clone() {
		BlockMacroComponent clone = (BlockMacroComponent) super.clone();
		clone.addEventListener(ON_AFTER_CLONE, new DataComponentAfterCloneEventListener());
		Events.postEvent(new Event(ON_AFTER_CLONE, clone));
		return clone;
	}

	/**
	 * 克隆后调用方法(在组合实现之后被调用)
	 */
	protected void doAfterClone() {

	}

	/**
	 * 数据组件克隆后事件, 仅执行一次
	 * 
	 * @author neeker
	 */
	private static class DataComponentAfterCloneEventListener implements EventListener<Event> {
		public void onEvent(Event event) throws Exception {
			final BlockMacroComponent clone = (BlockMacroComponent) event.getTarget();
			clone.doAfterClone();
			clone.removeEventListener(ON_AFTER_CLONE, this);
		}
	}

}
